#pragma once
#include <boost/optional.hpp>
#include "MouseRegion.h"
#include "MouseRegionPtr.h"
#include "InputAtom.h"
#include "ImportExport.h"

namespace ja2{ namespace sgp
{
	class ClockManager;

	//! Manage the mouse regions.
	class MouseRegionManager : boost::noncopyable
	{
		// Enums
	private:
		//! Actions.
		enum Action
		{
			A_MSYS_NO_ACTION = 0,
			A_MSYS_DO_MOVE = 1,
			A_MSYS_DO_LBUTTON_DWN = 2,
			A_MSYS_DO_LBUTTON_UP = 4,
			A_MSYS_DO_RBUTTON_DWN	= 8,
			A_MSYS_DO_RBUTTON_UP = 16,
			A_MSYS_DO_LBUTTON_REPEAT = 32,
			A_MSYS_DO_RBUTTON_REPEAT = 64,
			A_MSYS_DO_MBUTTON_DWN = 128,
			A_MSYS_DO_MBUTTON_UP = 256,
			A_MSYS_DO_MBUTTON_REPEAT = 512,
			A_MSYS_DO_X1BUTTON_DWN = 1024,
			A_MSYS_DO_X1BUTTON_UP = 2048,
			A_MSYS_DO_X1BUTTON_REPEAT = 4096,
			A_MSYS_DO_X2BUTTON_DWN = 8192,
			A_MSYS_DO_X2BUTTON_UP = 16384,
			A_MSYS_DO_X2BUTTON_REPEAT = 32768,
			A_MSYS_DO_WHEEL_UP = 65536,
			A_MSYS_DO_WHEEL_DOWN = 131072,
			A_MSYS_DO_BUTTONS = (A_MSYS_DO_LBUTTON_DWN | A_MSYS_DO_LBUTTON_UP | A_MSYS_DO_LBUTTON_REPEAT | \
								A_MSYS_DO_RBUTTON_DWN | A_MSYS_DO_RBUTTON_UP | A_MSYS_DO_RBUTTON_REPEAT |\
								A_MSYS_DO_MBUTTON_DWN | A_MSYS_DO_MBUTTON_UP | A_MSYS_DO_MBUTTON_REPEAT |\
								A_MSYS_DO_X1BUTTON_DWN | A_MSYS_DO_X1BUTTON_UP | A_MSYS_DO_X1BUTTON_REPEAT |\
								A_MSYS_DO_X2BUTTON_DWN | A_MSYS_DO_X2BUTTON_UP | A_MSYS_DO_X2BUTTON_REPEAT),
			A_MSYS_DO_WHEEL = (A_MSYS_DO_WHEEL_UP | A_MSYS_DO_WHEEL_DOWN),
		};
		//! Mouse system button masks.
		enum ButtonMask
		{
			BM_MSYS_LEFT_BUTTON = 1,
			BM_MSYS_RIGHT_BUTTON = 2
		};

		// Typedefs
	private:
		//! Region list.
		typedef std::list<MouseRegionPtr_t> MouseRegionList_t;

		// Attributes
	private:
		//! Clock manager.
		ClockManager &m_ClockManager;
		//! Actual mouse x position.
		/*!
			--REFERENCE--: MSYS_CurrentMX
		*/
		std::int_least16_t m_CurrentMX;
		//! Actual mouse y position.
		/*!
			--REFERENCE--: MSYS_CurrentMY
		*/
		std::int_least16_t m_CurrentMY;
		//! State of mouse buttons.
		std::int_least16_t m_CurrentButtons;
		//! Action.
		/*!
			--REFERENCE--: MSYS_Action
		*/
		std::uint_least16_t m_Action;
		//! Use handler.
		bool m_UseMouseHandlerHook;
		//! Mouse region priority list.
		/*!
			--REFERENCE--: MSYS_RegList
		*/
		MouseRegionList_t m_MouseRegionList;
		//! Grabbed region if any.
		/*!
			--REFERENCE--: MSYS_Mouse_Grabbed - Mouse is grabbed.
		*/
		MouseRegionList_t::iterator m_GrabRegion;
		//! Refresh update.
		bool m_RefreshUpdate;
		//! Current region.
		/*!
			--REFERENCE--: MSYS_CurrRegion
		*/
		MouseRegionList_t::iterator m_CurrentRegion;
		//! System region.
		/*!
			--REFERENCE--: MSYS_SystemBaseRegion
		*/
		MouseRegionList_t::iterator m_SystemRegion;
		//! Previous region?.
		/*!
			--REFERENCE--: MSYS_PrevRegion
		*/
		MouseRegionList_t::iterator m_PrevRegion;
		//! ???.
		/*!
			--REFERENCE--: gfClickedModeOn
		*/
		bool m_ClickedModeOn;
		//! ???.
		/*!
			--REFERENCE--: gusClickedIDNumber
		*/
		MouseRegionList_t::iterator m_ClickedRegion;
		//! Records and stores the last place the user clicked-down.
		/*!
			These values are compared to the current click to determine if a
			double click event has been detected.

			--REFERENCE--: gpRegionLastLButtonDown
		*/
		MouseRegionList_t::iterator m_RegionLastLButtonDown;
		//! Records and stores the last place the user clicked-release.
		/*!
			See \ref m_RegionLastLButtonDown.

			--REFERENCE--: gpRegionLastLButtonUp
		*/
		MouseRegionList_t::iterator m_RegionLastLButtonUp;
		//! Records and stores the last button down time.
		/*!
			See \ref m_RegionLastLButtonDown.

			--REFERENCE--: guiRegionLastLButtonDownTime
		*/
		std::uint_least32_t m_RegionLastLButtonDownTime;
		// Operations
	public:
		//! Add region to list.
		/*!
			The list is sorted by priority levels. If two entries have the same priority level, then the latest to enter the list gets the higher priority.
			--REFERENCE--: MSYS_AddRegionToList
		*/
		JA2_SGP_API void add_region(MouseRegionPtr_t const &pRegion);
		//! Hook to the SGP's mouse handler.
		/*!
			--REFERENCE--: MouseSystemHook, MSYS_SGP_Mouse_Handler_Hook.
		*/
		JA2_SGP_API void mouse_handler_hook(InputAtom::EventType Type, std::uint_least16_t XCoord, std::uint_least16_t YCoord, bool LeftButton, bool RightButton);
		/*!
			Searches the list for the highest priority region and updates it's info. It also dispatches	the callback functions
			--REFERENCE--: MSYS_UpdateMouseRegion
		*/
		JA2_SGP_API void update_mouse_region();
		//! Is action set.
		JA2_SGP_API bool is_action_set(Action Action_) const;
		//! Unset action.
		/*!
			--REFERENCE--: MSYS_Action &= (~XXX);
		*/
		JA2_SGP_API void unset_action(Action Action_);
		//! Find if region is in list.
		/*!
			Scan region list for presence of a node.

			--REFERENCE--: MSYS_RegionInList
		*/
		JA2_SGP_API bool region_in_list(MouseRegionPtr_t const &pRegion) const;
		//! Removes a region from the current list.
		/*!
			--REFERENCE--: MSYS_DeleteRegionFromList.
		*/
		JA2_SGP_API void delete_region_from_list(MouseRegionPtr_t const &pRegion);

	private:
		//! Is current region valid.
		bool current_region_valid() const;
		//! Return predefine invalid region.
		MouseRegionList_t::const_iterator invalid_region() const;
		//! Return predefine invalid region.
		MouseRegionList_t::iterator invalid_region();

		// Construction/Destruction
	public:
		JA2_SGP_API MouseRegionManager(ClockManager &ClockManager_);
		JA2_SGP_API ~MouseRegionManager();
	};
}/*sgp*/} /*ja2*/
